/*###################################################################*
#
# MP (Mitchell Pell) Base - CrossPlatform Base Utilities.
# Copyright (C) 2014  Mitchell Pell
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
####################################################################*/
#ifndef GL_TCP_CONNECTION_H
#define GL_TCP_CONNECTION_H

#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/asio.hpp>
#include "TcpData.h"
#include "../../../Base/Updateable.h"
#include "../../../Base/LockableMutex.h"

using boost::asio::ip::tcp;
using mp_base::interfaces::Updateable;
using mp_base::interfaces::LockableMutex;

#define MAKE_USHORT(a, b) \
	((unsigned short)(  ((unsigned char)(a))  |  ((unsigned short)((unsigned char)(b))  )<<8))

namespace mpgl_engine{ namespace application{ namespace net {


	enum class TcpConnectionState : char
	{
		IDLE				= 0x00,

		WRITING				= 0x01,
		READING				= 0x02,

		INPUT_READY			= 0x04,
		OUTPUT_READY		= 0x08,

		UNKNOWN				= 0xFF

	};
	/*! TcpConnectionState bitwise or operator */
	inline TcpConnectionState operator|(
		TcpConnectionState a, TcpConnectionState b){
		return static_cast<TcpConnectionState>(
			static_cast<int>(a) | 
			static_cast<int>(b));}
	/*! TcpConnectionState bitwise and operator */
	inline TcpConnectionState operator& (
		TcpConnectionState a, TcpConnectionState b){
		return static_cast<TcpConnectionState>(
			static_cast<int>(a) & 
			static_cast<int>(b));}
	/*! TcpConnectionState bitwise not operator  */
	inline TcpConnectionState operator~ (
		TcpConnectionState a){
		return static_cast<TcpConnectionState>(
			~static_cast<int>(a));}
	/*! TcpConnectionState xor operator */
	inline TcpConnectionState operator^ (
		TcpConnectionState a, TcpConnectionState b){
		return static_cast<TcpConnectionState>(
			static_cast<int>(a) ^ 
			static_cast<int>(b));}

	/*!----------------------------------------------------------------
	*	@class		TcpConnection
	*	@brief		This class represents a single TCP Connection. A
	*				single TCP Connection manages a socket connected
	*				to another IP endpoint.
	*				
	*
	*	@author		Mitchell Pell
	*	@date		01/04/2014
	*	@version	1.1
	*
	*	@revisions	Revision History:
	*
	*					- Version 1.1 01/07/2014
	*						-# Added boost async Send/Read data 
	*							functions (needs testing).
	*						-# Started boost async Send/Read data
	*							handler functions.
	*
	*					- Version 1.0 01/04/2014
	*						-# Initial Make
	*
	-----------------------------------------------------------------*/
	class TcpConnection : public Updateable, public LockableMutex
	{
	public:

		/*!  */
		TcpConnection(boost::asio::io_service& io_service)
			: m_socket(io_service), m_stopRequest(false), 
			  Updateable(), LockableMutex(){
			m_inData = new TcpData();
			m_outData = new TcpData();}

		/*!  */
		~TcpConnection(){ Disconnect();
			if (m_inData != NULL){ delete m_inData; }
			if (m_outData != NULL){ delete m_outData; }}

		/*!  */
		virtual void Update();

		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		>>> Connect & Disconnect
		>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

		/*!  */
		void Connect(tcp::resolver::iterator& endpoint_iterator){
			boost::asio::connect(m_socket, endpoint_iterator);}
		/*!  */
		void Disconnect(){ if (m_socket.is_open()){ m_socket.close();} }


		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		>>> TcpData Sending & Receiving
		>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

		/*!  */
		void SendData(bool clear = true);
		/*!  */
		void ReadData(bool concat = false);

		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		>>> Accessors & Mutators
		>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

		/*!  */
		tcp::socket& socket() { return m_socket; }

	protected:

		/*!  */
		virtual void HandleWrite(
			const boost::system::error_code& /*error*/,
			size_t	/*bytes_transferred*/);
		/*!  */
		virtual void HandleRead(
			const boost::system::error_code& /*error*/,
			size_t	/*bytes_transferred*/);

		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		>>> Members
		>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
	protected:
		/*! Socket to send/receive data to/from. */
		tcp::socket					m_socket;
		/*! TcpData handling Event for data received. */
		TcpData*					m_inData;
		/*! TcpData handling Event for data sending. */
		TcpData*					m_outData;
		/*!  */
		volatile TcpConnectionState	m_connectionState;
		/*! Session stop request flag.  */
		volatile bool				m_stopRequest;
	};

	typedef boost::shared_ptr<TcpConnection> spTcpConnection;
}}}

#endif